package com.zcy.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.fasterxml.jackson.core.JsonParser;
import com.zcy.annotation.HessianService;
import com.zcy.dynamic.DynamicCompileEngine;
import com.zcy.service.IMetaManageService;
import net.sf.json.JSONSerializer;
import net.sf.json.xml.XMLSerializer;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.hibernate.Session;
import org.hibernate.internal.SessionFactoryImpl;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;
import org.xml.sax.SAXException;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

/**
 * Created by join on 2017/6/28.
 * 元数据管理服务
 */
@HessianService("/meta/manageAPI")
@Service
@Transactional
public class MetaManageServiceImpl implements IMetaManageService {

    private final static String Server_JAVA_template_Content = getTmplate();
    private final static String SERVICE_JAVA_PACKAGE = MetaManageServiceImpl.class.getPackage().getName();


    @PersistenceContext
    private EntityManager em;

    @Autowired
    private DynamicCompileEngine dynamicEngine;


    @Override
    public Boolean saveOrUpdate(String metaInfo) {
        return saveOrUpdate(metaInfo,Boolean.FALSE);
    }

    @Override
    public Boolean saveOrUpdate(String metaInfo, boolean forceOverride) {
        //获取hibernate的session
        Session session = em.unwrap(Session.class);
        //获取hibernate 的 sessionfactory
        SessionFactoryImpl sessionFactory = (SessionFactoryImpl)session.getSessionFactory();


        try {
            //json转换XML
            String hbmFile = parseHbmFile(metaInfo);

            //装在数据结构元数据信息
            InputStream is = new ByteArrayInputStream(hbmFile.getBytes("utf-8"));
            //FileInputStream fis = new FileInputStream(hbmFile);
            sessionFactory.doLoadMetaData(is);

            //解析xml有多少实体对象
            is = new ByteArrayInputStream(hbmFile.getBytes("utf-8"));
            Document document = null;
            SAXReader saxReader = new SAXReader();
            document = saxReader.read(is);
            List<Node> entitys = document.selectNodes("/hibernate-mapping/class");

            for(Node node : entitys){

                if(node instanceof Element){
                    Element entity = (Element)node;
                    System.out.println(entity.attribute("entity-name").getValue());

                    //String entityName = "SysModf";
                    String entityName = entity.attribute("entity-name").getValue();
                    //生成java 服务类代码
                    String javaClassFullName = SERVICE_JAVA_PACKAGE + "." +initialstoUpperCase(entityName) + "Service";
                    String javaContent = generateJavaFileContent(entityName);

                    try {
                        Class.forName(javaClassFullName);
                        //如果已经存在则判断是否强制重写
                        if(forceOverride){
                            //编译并发布服务
                            dynamicEngine.compileToSpringBeanAndRegistService(javaClassFullName,javaContent,null);
                        }
                    }catch (ClassNotFoundException ex){
                        dynamicEngine.compileToSpringBeanAndRegistService(javaClassFullName,javaContent,null);
                    }
                }

            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return Boolean.FALSE;
        } catch (Exception e) {
            e.printStackTrace();
            return Boolean.FALSE;
        }


        return Boolean.TRUE;
    }

    @Override
    public Boolean delete(Long entityId) {
        return null;
    }

    protected String generateJavaFileContent(String entityName){
        //得到暴露API的名称
        String apiName = entityName.toLowerCase();

        //得到生成服务类的类名
        String serviceName = initialstoUpperCase(entityName);

        return Server_JAVA_template_Content.replaceAll("\\{#apiName#\\}",apiName)
                .replaceAll("\\{#serviceName#\\}",serviceName)
                .replaceAll("\\{#entityName#\\}",entityName);
    }

    /**
     * 字符串首字母大写转换
     * @param str
     * @return
     */
    private String initialstoUpperCase(String str){
//        char[] entityNameChars=str.toCharArray();
//        entityNameChars[0] = (entityNameChars[0] > 96) ? entityNameChars[0] - 32 : entityNameChars[0] ;
//        return String.valueOf(entityNameChars);

        return str.substring(0,1).toUpperCase() + str.substring(1);

    }

    /**
     * 获取服务类文件模版类型
     * @return
     */
    private static String getTmplate(){
        StringBuffer content = new StringBuffer();

        InputStreamReader read = null;
        BufferedReader bufferedReader = null;

        try {
            File file = ResourceUtils.getFile("classpath:DyServiceTemplate.tpl");
            read = new InputStreamReader(
                    new FileInputStream(file), "UTF-8");//考虑到编码格式
            bufferedReader = new BufferedReader(read);

            String lineTxt = null;
            while ((lineTxt = bufferedReader.readLine()) != null) {
                content.append(lineTxt);
            }
            read.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(bufferedReader!=null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(read != null){
                try {
                    read.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return content.toString();
    }

    /**
     * 根据json转hbm XML
     * @param jsonStr
     * @return
     */
    protected static String parseHbmFile(String jsonStr) throws IOException {

        Document document = DocumentHelper.createDocument();
        JSONObject jsonObj = JSON.parseObject(jsonStr, Feature.OrderedField);


        document.add(jSONObjectToXmlElement(jsonObj,"hibernate-mapping"));
        document.addDocType("hibernate-mapping", "-//Hibernate/Hibernate Mapping DTD 3.0//EN" ,"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd");

        OutputFormat format = new OutputFormat("    ",true);
        format.setEncoding("UTF-8");//设置编码格式
        format.setExpandEmptyElements(true);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

//        FileOutputStream fos = new FileOutputStream("/Users/join/Desktop/test123.hbm.xml");

        XMLWriter xmlWriter = new XMLWriter(baos,format);
        xmlWriter.write(document);
        xmlWriter.flush();
        xmlWriter.close();

        String xml = baos.toString("UTF-8");//document.asXML();
        return xml;//"/Users/join/Desktop/test123.hbm.xml";
    }


    /**
     * jsonOjbect 转 XML Element
     * @param jsonObject
     * @param nodeName
     * @return
     */
    private static Element jSONObjectToXmlElement(JSONObject jsonObject, String nodeName){
        Element ele = DocumentHelper.createElement(nodeName);

        Set<String> keys = jsonObject.keySet();

        for (String key :keys) {
            Object childObj = jsonObject.get(key);
            if(childObj instanceof JSONArray){
                JSONArray jsonArry = (JSONArray)childObj;
                jSONArrayToXmlElement(jsonArry,(jsonObj) ->{
                    ele.add(jSONObjectToXmlElement(jsonObj,key));
                });
            }else if(childObj instanceof JSONObject){
                JSONObject childJsonObj = (JSONObject)childObj;
                ele.add(jSONObjectToXmlElement(childJsonObj,key));
            }else{
                String val = jsonObject.getString(key);
                ele.addAttribute(key,val);
            }

//            if(key.startsWith("-")){//节点属性
//                String val = jsonObject.getString(key);
//                String name = key.substring(1);//转XML去掉属性前面的"-"标识
//                ele.addAttribute(name,val);
//            }else{//子节点
//
//                Object childObj = jsonObject.get(key);
//                if(childObj instanceof JSONArray){//数组节点
//                    JSONArray jsonArry = (JSONArray)childObj;
//                    jSONArrayToXmlElement(jsonArry,(jsonObj) ->{
//                        ele.add(jSONObjectToXmlElement(jsonObj,key));
//                    });
//                }else{
//                    JSONObject childJsonObj = (JSONObject)childObj;
//                    ele.add(jSONObjectToXmlElement(childJsonObj,key));
//                }
//            }
        }
        return ele;
    }

    /**
     * jsonArray 转 XML Element
     * @param jsonArray
     * @param action
     */
    private static void jSONArrayToXmlElement(JSONArray jsonArray,Consumer<? super JSONObject> action){
        jsonArray.forEach(item -> {
            if(item instanceof JSONArray){
                JSONArray items = (JSONArray)item;
                jSONArrayToXmlElement(items,action);
            }else{
                JSONObject jsonObj = (JSONObject)item;
                action.accept(jsonObj);
            }
        });
    }

    public static void main(String[] args){

        String xml = "{\"@default-cascade\":\"none\",\"@default-access\":\"property\",\"@default-lazy\":\"true\",\"@auto-import\":\"true\",\"class\":{\"@entity-name\":\"SysModf\",\"@table\":\"T_SYS_MODF\",\"@mutable\":\"true\",\"@polymorphism\":\"implicit\",\"@dynamic-update\":\"false\",\"@dynamic-insert\":\"false\",\"@select-before-update\":\"false\",\"@optimistic-lock\":\"version\",\"id\":{\"@name\":\"id\",\"@column\":\"ID\",\"generator\":[]},\"property\":[{\"@name\":\"name\",\"@column\":\"NAME\",\"@unique\":\"false\",\"@optimistic-lock\":\"true\",\"@lazy\":\"false\",\"@generated\":\"never\"},{\"@name\":\"address\",\"@column\":\"ADDRESS\",\"@unique\":\"false\",\"@optimistic-lock\":\"true\",\"@lazy\":\"false\",\"@generated\":\"never\"},{\"@name\":\"test\",\"@column\":\"TEST\",\"@unique\":\"false\",\"@optimistic-lock\":\"true\",\"@lazy\":\"false\",\"@generated\":\"never\"},{\"@name\":\"ke\",\"@column\":\"KE\",\"@unique\":\"false\",\"@optimistic-lock\":\"true\",\"@lazy\":\"false\",\"@generated\":\"never\"},{\"@name\":\"ke1\",\"@column\":\"KE1\",\"@unique\":\"false\",\"@optimistic-lock\":\"true\",\"@lazy\":\"false\",\"@generated\":\"never\"},{\"@name\":\"status\",\"@column\":\"status\",\"@unique\":\"false\",\"@optimistic-lock\":\"true\",\"@lazy\":\"false\",\"@generated\":\"never\"},{\"@name\":\"createDateTime\",\"@column\":\"CREATETIME\",\"@unique\":\"false\",\"@optimistic-lock\":\"true\",\"@lazy\":\"false\",\"@generated\":\"never\"},{\"@name\":\"lastModifyDateTime\",\"@column\":\"LASTMODIFY\",\"@unique\":\"false\",\"@optimistic-lock\":\"true\",\"@lazy\":\"false\",\"@generated\":\"never\"}]}}";

        String json = "{\"hibernate-mapping\":{\"class\":{\"-entity-name\":\"SysModf\",\"-table\":\"T_SYS_MODF\",\"id\":{\"-name\":\"id\",\"-type\":\"long\",\"-column\":\"ID\",\"generator\":{\"-class\":\"com.zcy.util.IdentifierGenerator\"}},\"property\":[{\"-name\":\"name\",\"-column\":\"NAME\",\"-type\":\"string\"},{\"-name\":\"address\",\"-column\":\"ADDRESS\",\"-type\":\"string\"},{\"-name\":\"test\",\"-column\":\"TEST\",\"-type\":\"string\"},{\"-name\":\"ke\",\"-column\":\"KE\",\"-type\":\"string\"},{\"-name\":\"ke1\",\"-column\":\"KE1\",\"-type\":\"string\"},{\"-name\":\"status\",\"-column\":\"status\",\"-type\":\"int\"},{\"-name\":\"createDateTime\",\"-column\":\"CREATETIME\",\"-type\":\"timestamp\"},{\"-name\":\"lastModifyDateTime\",\"-column\":\"LASTMODIFY\",\"-type\":\"timestamp\"}]}}}";

        String json1 = "{\"class\":{\"-entity-name\":\"SysModf\",\"-table\":\"T_SYS_MODF\",\"id\":{\"-name\":\"id\",\"-type\":\"long\",\"-column\":\"ID\",\"generator\":{\"-class\":\"com.zcy.util.IdentifierGenerator\"}},\"property\":[{\"-name\":\"name\",\"-column\":\"NAME\",\"-type\":\"string\"},{\"-name\":\"address\",\"-column\":\"ADDRESS\",\"-type\":\"string\"},{\"-name\":\"test\",\"-column\":\"TEST\",\"-type\":\"string\"},{\"-name\":\"ke\",\"-column\":\"KE\",\"-type\":\"string\"},{\"-name\":\"ke1\",\"-column\":\"KE1\",\"-type\":\"string\"},{\"-name\":\"status\",\"-column\":\"status\",\"-type\":\"int\"},{\"-name\":\"createDateTime\",\"-column\":\"CREATETIME\",\"-type\":\"timestamp\"},{\"-name\":\"lastModifyDateTime\",\"-column\":\"LASTMODIFY\",\"-type\":\"timestamp\"}]}}";

        String json2 = "{\"class\":[{\"-entity-name\":\"SysModf\",\"-table\":\"T_SYS_MODF\",\"id\":{\"-name\":\"id\",\"-type\":\"long\",\"-column\":\"ID\",\"generator\":{\"-class\":\"com.zcy.util.IdentifierGenerator\"}},\"property\":[{\"-name\":\"name\",\"-column\":\"NAME\",\"-type\":\"string\"},{\"-name\":\"address\",\"-column\":\"ADDRESS\",\"-type\":\"string\"},{\"-name\":\"test\",\"-column\":\"TEST\",\"-type\":\"string\"},{\"-name\":\"ke\",\"-column\":\"KE\",\"-type\":\"string\"},{\"-name\":\"ke1\",\"-column\":\"KE1\",\"-type\":\"string\"},{\"-name\":\"status\",\"-column\":\"status\",\"-type\":\"int\"},{\"-name\":\"createDateTime\",\"-column\":\"CREATETIME\",\"-type\":\"timestamp\"},{\"-name\":\"lastModifyDateTime\",\"-column\":\"LASTMODIFY\",\"-type\":\"timestamp\"}]},{\"-entity-name\":\"SysModfItem\",\"-table\":\"T_SYS_MODF_item\",\"id\":{\"-name\":\"id\",\"-type\":\"long\",\"-column\":\"ID\",\"generator\":{\"-class\":\"com.zcy.util.IdentifierGenerator\"}},\"property\":[{\"-name\":\"name\",\"-column\":\"NAME\",\"-type\":\"string\"},{\"-name\":\"address\",\"-column\":\"ADDRESS\",\"-type\":\"string\"},{\"-name\":\"test\",\"-column\":\"TEST\",\"-type\":\"string\"},{\"-name\":\"ke\",\"-column\":\"KE\",\"-type\":\"string\"},{\"-name\":\"ke1\",\"-column\":\"KE1\",\"-type\":\"string\"},{\"-name\":\"status\",\"-column\":\"status\",\"-type\":\"int\"},{\"-name\":\"createDateTime\",\"-column\":\"CREATETIME\",\"-type\":\"timestamp\"},{\"-name\":\"lastModifyDateTime\",\"-column\":\"LASTMODIFY\",\"-type\":\"timestamp\"}]}]}";
        try {
            System.out.println(parseHbmFile(json2));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
